package com.wande.dataplatform.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.wande.common.core.exception.ServiceException;
import com.wande.common.mybatis.core.page.PageQuery;
import com.wande.common.mybatis.core.page.TableDataInfo;
import com.wande.common.satoken.utils.LoginHelper;
import com.wande.dataplatform.common.enums.DataPlatformErrorCode;
import com.wande.dataplatform.domain.ApiCallLog;
import com.wande.dataplatform.domain.DataApi;
import com.wande.dataplatform.domain.bo.DataApiBo;
import com.wande.dataplatform.domain.dto.ApiResponseDTO;
import com.wande.dataplatform.domain.dto.ApiStatisticsDTO;
import com.wande.dataplatform.domain.vo.ApiCallLogVO;
import com.wande.dataplatform.domain.vo.DataApiVO;
import com.wande.dataplatform.mapper.ApiCallLogMapper;
import com.wande.dataplatform.mapper.DataApiMapper;
import com.wande.dataplatform.service.IDataApiService;
import com.wande.dataplatform.service.IDorisService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 数据服务API Service实现
 *
 * @author wande
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class DataApiServiceImpl implements IDataApiService {

    private final DataApiMapper dataApiMapper;
    private final ApiCallLogMapper apiCallLogMapper;
    private final IDorisService dorisService;

    private static final Pattern PARAM_PATTERN = Pattern.compile("#\\{(\\w+)}");

    @Override
    public TableDataInfo<DataApiVO> queryPageList(DataApiBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<DataApi> wrapper = buildQueryWrapper(bo);
        Page<DataApiVO> page = dataApiMapper.selectVoPage(pageQuery.build(), wrapper);
        return TableDataInfo.build(page);
    }

    @Override
    public List<DataApiVO> queryList(DataApiBo bo) {
        LambdaQueryWrapper<DataApi> wrapper = buildQueryWrapper(bo);
        return dataApiMapper.selectVoList(wrapper);
    }

    private LambdaQueryWrapper<DataApi> buildQueryWrapper(DataApiBo bo) {
        return Wrappers.lambdaQuery(DataApi.class)
            .like(StrUtil.isNotBlank(bo.getName()), DataApi::getName, bo.getName())
            .like(StrUtil.isNotBlank(bo.getPath()), DataApi::getPath, bo.getPath())
            .eq(StrUtil.isNotBlank(bo.getStatus()), DataApi::getStatus, bo.getStatus())
            .eq(bo.getProjectId() != null, DataApi::getProjectId, bo.getProjectId())
            .orderByDesc(DataApi::getCreateTime);
    }

    @Override
    public DataApiVO queryById(Long id) {
        return dataApiMapper.selectVoById(id);
    }

    @Override
    public DataApiVO queryByPathAndVersion(String path, String version) {
        LambdaQueryWrapper<DataApi> wrapper = Wrappers.lambdaQuery(DataApi.class)
            .eq(DataApi::getPath, path)
            .eq(DataApi::getVersion, version)
            .eq(DataApi::getStatus, "PUBLISHED");
        return dataApiMapper.selectVoOne(wrapper);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long insertByBo(DataApiBo bo) {
        // 检查路径和版本是否已存在
        LambdaQueryWrapper<DataApi> wrapper = Wrappers.lambdaQuery(DataApi.class)
            .eq(DataApi::getPath, bo.getPath())
            .eq(DataApi::getVersion, bo.getVersion());
        if (dataApiMapper.exists(wrapper)) {
            throw new ServiceException("API路径和版本已存在");
        }

        DataApi entity = BeanUtil.toBean(bo, DataApi.class);
        if (StrUtil.isBlank(entity.getStatus())) {
            entity.setStatus("DRAFT");
        }
        if (StrUtil.isBlank(entity.getVersion())) {
            entity.setVersion("1.0");
        }
        if (entity.getRateLimit() == null) {
            entity.setRateLimit(100);
        }

        dataApiMapper.insert(entity);
        return entity.getId();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updateByBo(DataApiBo bo) {
        DataApi entity = BeanUtil.toBean(bo, DataApi.class);
        return dataApiMapper.updateById(entity) > 0;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean deleteById(Long id) {
        DataApi api = dataApiMapper.selectById(id);
        if (api == null) {
            throw new ServiceException(DataPlatformErrorCode.API_NOT_FOUND.getMessage());
        }
        if ("PUBLISHED".equals(api.getStatus())) {
            throw new ServiceException("已发布的API不能删除，请先下线");
        }
        return dataApiMapper.deleteById(id) > 0;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean deleteByIds(List<Long> ids) {
        for (Long id : ids) {
            deleteById(id);
        }
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean publishApi(Long id) {
        DataApi api = dataApiMapper.selectById(id);
        if (api == null) {
            throw new ServiceException(DataPlatformErrorCode.API_NOT_FOUND.getMessage());
        }

        // 验证SQL模板
        validateSqlTemplate(api.getSqlTemplate());

        api.setStatus("PUBLISHED");
        return dataApiMapper.updateById(api) > 0;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean offlineApi(Long id) {
        DataApi api = dataApiMapper.selectById(id);
        if (api == null) {
            throw new ServiceException(DataPlatformErrorCode.API_NOT_FOUND.getMessage());
        }

        api.setStatus("OFFLINE");
        return dataApiMapper.updateById(api) > 0;
    }

    @Override
    public ApiResponseDTO callApi(String path, String version, Map<String, Object> params, String token) {
        long startTime = System.currentTimeMillis();
        String caller = "anonymous";
        String callerIp = "unknown";

        try {
            // 获取调用者信息
            try {
                caller = LoginHelper.getUsername();
            } catch (Exception e) {
                log.debug("获取用户名失败", e);
            }

            // 查询API
            DataApiVO api = queryByPathAndVersion(path, version);
            if (api == null) {
                throw new ServiceException(DataPlatformErrorCode.API_NOT_FOUND.getMessage());
            }

            if (!"PUBLISHED".equals(api.getStatus())) {
                throw new ServiceException(DataPlatformErrorCode.API_NOT_PUBLISHED.getMessage());
            }

            // 鉴权验证
            validateAuth(api, token);

            // 限流检查
            checkRateLimit(api.getId(), api.getRateLimit());

            // 执行SQL查询
            String sql = buildSql(api.getSqlTemplate(), params);
            List<Map<String, Object>> data = dorisService.executeQuery(sql);

            // 应用脱敏规则
            if (StrUtil.isNotBlank(api.getDesensitizeRules())) {
                data = applyDesensitize(data, api.getDesensitizeRules());
            }

            long responseTime = System.currentTimeMillis() - startTime;

            // 记录日志
            logApiCall(api.getId(), api.getName(), api.getPath(), caller, callerIp,
                JSONUtil.toJsonStr(params), JSONUtil.toJsonStr(data), 200, responseTime, null);

            return ApiResponseDTO.builder()
                .code(200)
                .message("success")
                .data(data)
                .total((long) data.size())
                .responseTime(responseTime)
                .build();

        } catch (Exception e) {
            long responseTime = System.currentTimeMillis() - startTime;
            log.error("API调用失败: path={}, version={}", path, version, e);

            // 记录错误日志
            logApiCall(null, null, path, caller, callerIp,
                JSONUtil.toJsonStr(params), null, 500, responseTime, e.getMessage());

            return ApiResponseDTO.builder()
                .code(500)
                .message(e.getMessage())
                .responseTime(responseTime)
                .build();
        }
    }

    @Override
    public ApiResponseDTO testApi(Long id, Map<String, Object> params) {
        long startTime = System.currentTimeMillis();

        try {
            DataApiVO api = queryById(id);
            if (api == null) {
                throw new ServiceException(DataPlatformErrorCode.API_NOT_FOUND.getMessage());
            }

            // 执行SQL查询
            String sql = buildSql(api.getSqlTemplate(), params);
            List<Map<String, Object>> data = dorisService.executeQuery(sql);

            long responseTime = System.currentTimeMillis() - startTime;

            return ApiResponseDTO.builder()
                .code(200)
                .message("success")
                .data(data)
                .total((long) data.size())
                .responseTime(responseTime)
                .build();

        } catch (Exception e) {
            long responseTime = System.currentTimeMillis() - startTime;
            log.error("API测试失败: id={}", id, e);

            return ApiResponseDTO.builder()
                .code(500)
                .message(e.getMessage())
                .responseTime(responseTime)
                .build();
        }
    }

    @Override
    public ApiStatisticsDTO getStatistics(Long id, LocalDate startDate, LocalDate endDate) {
        LocalDateTime startTime = startDate.atStartOfDay();
        LocalDateTime endTime = endDate.atTime(LocalTime.MAX);

        Long totalCalls = apiCallLogMapper.countCalls(id, startTime, endTime);
        Long successCalls = apiCallLogMapper.countSuccessCalls(id, startTime, endTime);
        Long failedCalls = totalCalls - successCalls;

        BigDecimal successRate = BigDecimal.ZERO;
        if (totalCalls > 0) {
            successRate = BigDecimal.valueOf(successCalls)
                .divide(BigDecimal.valueOf(totalCalls), 4, RoundingMode.HALF_UP)
                .multiply(BigDecimal.valueOf(100));
        }

        Long avgResponseTime = apiCallLogMapper.avgResponseTime(id, startTime, endTime);
        Long maxResponseTime = apiCallLogMapper.maxResponseTime(id, startTime, endTime);
        Long minResponseTime = apiCallLogMapper.minResponseTime(id, startTime, endTime);

        // 统计今日、本周、本月调用次数
        LocalDateTime todayStart = LocalDate.now().atStartOfDay();
        LocalDateTime todayEnd = LocalDateTime.now();
        Long todayCalls = apiCallLogMapper.countCalls(id, todayStart, todayEnd);

        LocalDateTime weekStart = LocalDate.now().minusDays(7).atStartOfDay();
        Long weekCalls = apiCallLogMapper.countCalls(id, weekStart, todayEnd);

        LocalDateTime monthStart = LocalDate.now().minusDays(30).atStartOfDay();
        Long monthCalls = apiCallLogMapper.countCalls(id, monthStart, todayEnd);

        return ApiStatisticsDTO.builder()
            .totalCalls(totalCalls)
            .successCalls(successCalls)
            .failedCalls(failedCalls)
            .successRate(successRate)
            .avgResponseTime(avgResponseTime != null ? avgResponseTime : 0L)
            .maxResponseTime(maxResponseTime != null ? maxResponseTime : 0L)
            .minResponseTime(minResponseTime != null ? minResponseTime : 0L)
            .todayCalls(todayCalls)
            .weekCalls(weekCalls)
            .monthCalls(monthCalls)
            .build();
    }

    @Override
    public TableDataInfo<ApiCallLogVO> queryCallLogs(Long apiId, PageQuery pageQuery) {
        LambdaQueryWrapper<ApiCallLog> wrapper = Wrappers.lambdaQuery(ApiCallLog.class)
            .eq(apiId != null, ApiCallLog::getApiId, apiId)
            .orderByDesc(ApiCallLog::getCallTime);
        Page<ApiCallLogVO> page = apiCallLogMapper.selectVoPage(pageQuery.build(), wrapper);
        return TableDataInfo.build(page);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void logApiCall(Long apiId, String apiName, String apiPath, String caller, String callerIp,
                           String requestParams, String responseData, Integer statusCode,
                           Long responseTime, String errorMessage) {
        ApiCallLog log = new ApiCallLog();
        log.setApiId(apiId);
        log.setApiName(apiName);
        log.setApiPath(apiPath);
        log.setCaller(caller);
        log.setCallerIp(callerIp);
        log.setRequestParams(requestParams);
        log.setResponseData(responseData);
        log.setStatusCode(statusCode);
        log.setResponseTime(responseTime);
        log.setErrorMessage(errorMessage);
        log.setCallTime(LocalDateTime.now());
        apiCallLogMapper.insert(log);
    }

    /**
     * 验证SQL模板
     */
    private void validateSqlTemplate(String sqlTemplate) {
        if (StrUtil.isBlank(sqlTemplate)) {
            throw new ServiceException("SQL模板不能为空");
        }
        // 简单验证：禁止DELETE、UPDATE、DROP等危险操作
        String upperSql = sqlTemplate.toUpperCase();
        if (upperSql.contains("DELETE") || upperSql.contains("UPDATE") ||
            upperSql.contains("DROP") || upperSql.contains("TRUNCATE") ||
            upperSql.contains("ALTER") || upperSql.contains("CREATE")) {
            throw new ServiceException("SQL模板不能包含DELETE、UPDATE、DROP等危险操作");
        }
    }

    /**
     * 构建SQL
     */
    private String buildSql(String sqlTemplate, Map<String, Object> params) {
        if (params == null) {
            params = new HashMap<>();
        }

        String sql = sqlTemplate;
        Matcher matcher = PARAM_PATTERN.matcher(sqlTemplate);
        while (matcher.find()) {
            String paramName = matcher.group(1);
            Object paramValue = params.get(paramName);
            if (paramValue == null) {
                throw new ServiceException("缺少参数: " + paramName);
            }
            // 简单的参数替换，实际应该使用PreparedStatement防止SQL注入
            String replacement = paramValue.toString();
            if (paramValue instanceof String) {
                replacement = "'" + replacement.replace("'", "''") + "'";
            }
            sql = sql.replace("#{" + paramName + "}", replacement);
        }
        return sql;
    }

    /**
     * 验证鉴权
     */
    private void validateAuth(DataApiVO api, String token) {
        if ("TOKEN".equals(api.getAuthType())) {
            if (StrUtil.isBlank(token)) {
                throw new ServiceException(DataPlatformErrorCode.API_AUTH_FAILED.getMessage());
            }
            // 这里应该验证token的有效性
            // 简化处理，实际应该调用认证服务
        }
    }

    /**
     * 检查限流
     */
    private void checkRateLimit(Long apiId, Integer rateLimit) {
        // 简化处理，实际应该使用Redis实现分布式限流
        // 这里只是示例
    }

    /**
     * 应用脱敏规则
     */
    private List<Map<String, Object>> applyDesensitize(List<Map<String, Object>> data, String desensitizeRules) {
        // 简化处理，实际应该根据规则进行脱敏
        // 这里只是示例
        return data;
    }
}
